home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / PROGTOOL / PASSDK30.ZIP;1 / DISK1.ZIP / PAS / SUBS / PCM / PCMOLDC.C < prev    next >
Encoding:
Text File  |  1993-02-09  |  26.9 KB  |  872 lines

  1. /*$Author:   DCODY  $*/
  2. /*$Date:   09 Feb 1993 08:26:30  $*/
  3. /*$Header:   X:/sccs/pcm/pcmoldc.c_v   1.0   09 Feb 1993 08:26:30   DCODY  $*/
  4. /*$Log:   X:/sccs/pcm/pcmoldc.c_v  $
  5.  * 
  6.  *    Rev 1.0   09 Feb 1993 08:26:30   DCODY
  7.  * Initial revision.
  8.  * 
  9.  *    Rev 1.12   03 Feb 1993 12:09:48   DCODY
  10.  * just more debug statements added, no real changes.
  11.  * 
  12.  *    Rev 1.11   06 Jan 1993 15:26:34   DCODY
  13.  * corrected two bugs: ContinueThisBlockOutput had a bug in an IF statement
  14.  * where it evaluated the two expressions incorrectly. The second bug was
  15.  * in QueryPCMStream, which returned an incorrect value. 
  16.  * Also, some debugging info was added, but commented out.
  17.  * 
  18.  *    Rev 1.10   08 Dec 1992 17:13:54   DCODY
  19.  * added a new routine: QueryPCMStream to return the number of blocks
  20.  * buffered.
  21.  * Also added, but commented out some debugging code.
  22.  * 
  23.  *    Rev 1.9   20 Oct 1992 10:07:38   DCODY
  24.  * lots of cosmetic changes. all variables are now initialized so they
  25.  * have memory allocated at compile time.
  26.  * 
  27.  *    Rev 1.8   06 Oct 1992 15:59:50   DCODY
  28.  * major changes so code is free (freer) from the C libraries. Replaced
  29.  * malloc and fread/fwrite.
  30.  * 
  31.  *    Rev 1.7   01 Oct 1992 12:05:02   DCODY
  32.  * next stage of completion for PlayThisBlock, RecordThisBlock, etc.
  33.  * 
  34.  *    Rev 1.6   23 Sep 1992 10:56:34   DCODY
  35.  * more work on playthisblock, continuethisblock...
  36.  * 
  37.  *    Rev 1.5   26 Aug 1992 10:57:30   DCODY
  38.  * Added Playthisblock and RecordThisBlock
  39.  * 
  40.  *    Rev 1.4   12 Aug 1992 17:10:30   DCODY
  41.  * major change to eliminate the foreground buffers.
  42.  * 
  43.  *    Rev 1.3   24 Jul 1992 15:36:14   DCODY
  44.  * changed _fmemcpy to _rfmemcpy
  45.  * 
  46.  *    Rev 1.2   17 Jul 1992 14:22:50   DCODY
  47.  * InitMVSound() now performed within OpenPCMBuffering().
  48.  * 
  49.  *    Rev 1.1   23 Jun 1992 17:11:42   DCODY
  50.  * PAS2 update
  51.  * 
  52.  *    Rev 1.0   15 Jun 1992 09:44:38   BCRANE
  53.  * Initial revision.
  54. */
  55. /*$Logfile:   X:/sccs/pcm/pcmoldc.c_v  $*/
  56. /*$Modtimes$*/
  57. /*$Revision:   1.0  $*/
  58. /*$Workfile:   pcmoldc.c  $*/
  59.  
  60.  
  61. ;    /*\
  62. ;---|*|----====< PCMIOC.C >====----
  63. ;---|*|
  64. ;---|*| These routines maintain DMA controlled I/O of the Audio Spectrum
  65. ;---|*|
  66. ;---|*| Copyright (c) 1991, Media Vision, Inc. All rights reserved.
  67. ;---|*|
  68. ;    \*/
  69.  
  70. #include <stdio.h>
  71. #include <stdlib.h>
  72.  
  73. #include "pcmio.h"
  74. #include "common.h"
  75. #include "mvsound.h"
  76.  
  77. ;    /*\
  78. ;---|*|-----------====< T H E O R Y   O F    O P E R A T I O N >====------------
  79. ;---|*|
  80. ;---|*| The best DMA controlled PCM output requires a continuous stream of data
  81. ;---|*| to be available in a real-time environment.
  82. ;---|*|
  83. ;---|*| DMA controlled PCM input, with the same real-time requirements, needs
  84. ;---|*| to be able to keep storing data into memory without pausing.
  85. ;---|*|
  86. ;---|*| The following approach is designed to allow the DMA to be setup in
  87. ;---|*| "auto-initialize" mode, thereby guarenteeing continuous play/record.
  88. ;---|*|
  89. ;---|*| To keep the DMA running, multiple divisions of the DMA buffer are
  90. ;---|*| used to keep the data moving. Due to the fact that DOS is neither
  91. ;---|*| a real-time, or re-entrant operating system, this code divides up
  92. ;---|*| the buffer management tasks into a "foreground" and "background" task.
  93. ;---|*|
  94. ;---|*| A sample buffer count timer on the Audio Spectrum is used to interrupt
  95. ;---|*| the CPU when a DMA buffer division has filled or emptied. For our
  96. ;---|*| purposes here, this amount may be 1/2, 1/4, 1/8th or some smaller
  97. ;---|*| division of the whole DMA buffer. Note: judgement must be used here
  98. ;---|*| in selecting the DMA buffer size, and the integral division. Too small
  99. ;---|*| of an integral may result in broken DMA I/O. A buffer too large never
  100. ;---|*| hurts anything. (it just reduces the amount of available memory).
  101. ;---|*|
  102. ;---|*|                 ----====< PCM OUTPUT >====----
  103. ;---|*|
  104. ;---|*| To perform PCM output ("play"), A linked list of buffer pointers is
  105. ;---|*| used to fill the DMA buffer by the foregound task. As the DMA runs,
  106. ;---|*| it will send the buffer contents to the audio card. Here is a visual:
  107. ;---|*|
  108. ;---|*|                            
  109. ;---|*|                      Foreground Loads
  110. ;---|*|                        the Top Level
  111. ;---|*|                          Buffers
  112. ;---|*|                            
  113. ;---|*|                        ⁄ƒ¬ƒ¬ƒ¬ƒ¬ƒø
  114. ;---|*|      DMA Level Buffers ≥ ≥ ≥ ≥ ≥ ≥
  115. ;---|*|                        ¿ƒ¡ƒ¡ƒ¡ƒ¡ƒŸ
  116. ;---|*|                            
  117. ;---|*|                        ⁄ƒƒƒƒƒƒƒƒƒø
  118. ;---|*|                        ≥hardware ≥
  119. ;---|*|                        ¿“““ƒƒƒƒƒƒŸ
  120. ;---|*|
  121. ;---|*| To actually start the output, the foreground task loads it's
  122. ;---|*| buffers, then starts the DMA to play the buffer. The background
  123. ;---|*| task only indicates when each block is played. It will shut down
  124. ;---|*| the DMA if no more data is present in the buffers.
  125. ;---|*|
  126. ;---|*| If the foreground task can keep the linked list of buffers full,
  127. ;---|*| there should be non-stop PCM output (Good!). If the foreground task
  128. ;---|*| does not keep up, the background task will be forced to stop the
  129. ;---|*| the DMA, thereby causing a break in the output (Bad!). Once the DMA
  130. ;---|*| has stopped, the foreground task will have to restart the DMA a
  131. ;---|*| second time to continue the flow of data.
  132. ;---|*|
  133. ;---|*|                 ----====< PCM INPUT >====----
  134. ;---|*|
  135. ;---|*| To perform PCM input ("record"), the same linked list of buffers
  136. ;---|*| are also used. This buffer is filled with sampled data from the
  137. ;---|*| hardware. The background process will increment a global variable for
  138. ;---|*| each buffer filled. The foreground routine must extract each buffer
  139. ;---|*| and process it (copy to memory, or write it to disk). Here is a visual:
  140. ;---|*|
  141. ;---|*|                            
  142. ;---|*|                      Foreground unloads
  143. ;---|*|                        the Top Level
  144. ;---|*|                          Buffers
  145. ;---|*|                            
  146. ;---|*|                        ⁄ƒ¬ƒ¬ƒ¬ƒ¬ƒø
  147. ;---|*|      DMA Level Buffers ≥ ≥ ≥ ≥ ≥ ≥
  148. ;---|*|                        ¿ƒ¡ƒ¡ƒ¡ƒ¡ƒŸ
  149. ;---|*|                            
  150. ;---|*|                        ⁄ƒƒƒƒƒƒƒƒƒø
  151. ;---|*|                        ≥hardware ≥
  152. ;---|*|                        ¿“““ƒƒƒƒƒƒŸ
  153. ;---|*|
  154. ;---|*| To actually start the input, the foreground starts the DMA running to
  155. ;---|*| begin the transfer. The background task increments the global variable
  156. ;---|*| as each interrupt occurs. If all the buffers are full, the DMA transfer
  157. ;---|*| is terminated. The foreground routine must poll this variable to keep
  158. ;---|*| the data moving out of the DMA buffer.
  159. ;---|*|
  160. ;---|*| If the foreground task can keep the linked list of buffers empty,
  161. ;---|*| there should be non-stop PCM input (Good!). If the foreground task
  162. ;---|*| does not keep up, the background task will be forced to stop the
  163. ;---|*| the DMA, thereby causing a break in the input (Bad!). Once the DMA
  164. ;---|*| has stopped, the foreground task will have to restart the DMA tranfer
  165. ;---|*| a second time to restart the DMA.
  166. ;---|*|
  167. ;---|*|                 ----====< DATA VARIABLES >====----
  168. ;---|*|
  169. ;---|*| The following is a description of the variables shared between the
  170. ;---|*| foreground and background tasks. There are three global variables,
  171. ;---|*| and a linked list of buffers shared between the two tasks.
  172. ;---|*|
  173. ;---|*| The linked list of buffers uses a "header" to each buffer. This
  174. ;---|*| header holds the information for linking to the next buffer, whether
  175. ;---|*| the buffer is full or empty, and the count of bytes in the buffer.
  176. ;---|*|
  177. ;---|*| typedef struct _buffptr {
  178. ;---|*|     int status;                 /* 0=empty, 1=full                 * /
  179. ;---|*|     int count;                    /* # of bytes in the buffer      * /
  180. ;---|*|     int size;                    /* total size of read data         * /
  181. ;---|*|     char huge *buffer;            /* pointer to buffer data         * /
  182. ;---|*|     struct _buffptr, *nextptr;    /* pointer to next buffer         * /
  183. ;---|*|
  184. ;---|*| } BuffData,*BuffPtr;
  185. ;---|*|
  186. ;---|*| BuffPtr HeadOfBuffers;            /* global variable head pointer  * /
  187. ;---|*| int BufferDataCount;            /* # of full DMA buffers parts     * /
  188. ;---|*| int DMARunning;                 /* DMA status (0=off,1=running)  * /
  189. ;---|*| char far *StartOfDMABuffer;     /* start of actual DMA buffer     * /
  190. ;---|*| int ProcessedBlockCount;        /* # of blocks DMA handled         * /
  191. ;---|*|
  192. ;---|*| "HeadOfBuffers" points to the first buffer in the linked list.
  193. ;---|*|
  194. ;---|*|       This linked list is made up of structures containing the buffer
  195. ;---|*|     data and other information. The last entry in the list points
  196. ;---|*|     back to the first entry, thereby creating a circular linked
  197. ;---|*|     list.
  198. ;---|*|       Each buffer has a status word: 0=empty,1=full.
  199. ;---|*|       The count indicates the # of bytes in the buffer. This count
  200. ;---|*|     is used to communication between the foreground and background
  201. ;---|*|     process that data is available. For output, the count tells the
  202. ;---|*|     background that data is available to be loaded in the DMA buffer.
  203. ;---|*|     For input, the count tells the foreground process that there is
  204. ;---|*|     data to be written to disk.
  205. ;---|*|
  206. ;---|*| "BufferDataCount" is the key handshaking variable between the
  207. ;---|*|     foreground and background processes. It indicates how many DMA
  208. ;---|*|     buffers divisions contain data.
  209. ;---|*|
  210. ;---|*|     For output, it holds a count of DMA divisions hold data. This
  211. ;---|*|     global variable is incremented each time a buffer is loaded by
  212. ;---|*|     the foreground task, and decremented when a buffer is emptied
  213. ;---|*|     by the background task.
  214. ;---|*|
  215. ;---|*|     For input, it holds the number of buffers with data in the DMA
  216. ;---|*|     buffer. It is incremented by the background process and
  217. ;---|*|     decremented by the foreground process.
  218. ;---|*|
  219. ;---|*| "DMARunning" is set to true or false depending upon the state
  220. ;---|*|     of the DMA channel. It is set TRUE when the DMA is running (either
  221. ;---|*|     playing or recording), and FALSE when the DMA is turned off.
  222. ;---|*|
  223. ;---|*| "ProcessedBlockCount" is the running total of blocks the DMA has
  224. ;---|*|     processed from the last Start I/O call.
  225. ;---|*|
  226. ;---|*|     For input, this is the total number of dma divisions filled
  227. ;---|*|     by the DMA.
  228. ;---|*|
  229. ;---|*|     For output, this is the total number of blocks loaded into
  230. ;---|*|     the DMA buffer.
  231. ;---|*|
  232. ;---|*| "StartOfDMABuffer" points to the first byte of the DMA circular buffer.
  233. ;---|*|
  234. ;---|*| The following routines provide a high level interface to DMA driven
  235. ;---|*| PCM output:
  236. ;---|*|
  237. ;---|*| int  OpenPCMBuffering  ( int, int, int, int )
  238. ;---|*|
  239. ;---|*|         This routine is the first routine to be called. It sets
  240. ;---|*|         up the DMA channel, IRQ, and allocates memory for the buffers.
  241. ;---|*|
  242. ;---|*| int PCMState ( int, int, int, int )
  243. ;---|*|
  244. ;---|*|         This routine passes in the sample rate, stereo/mono flag,
  245. ;---|*|         the compression type (0 for 8 bit, 1 for for 4 bit),
  246. ;---|*|         and the PCM data sample size (8 or 16).
  247. ;---|*|
  248. ;---|*| int  StartFileInput    ( FILE *f )
  249. ;---|*|
  250. ;---|*|         This routine begins recording the PCM data to the disk file.
  251. ;---|*|         The routine returns immediately. The routine,
  252. ;---|*|         "ContinueFileInput" must be called to continue moving data
  253. ;---|*|         from the DMA buffer to to the disk.
  254. ;---|*|
  255. ;---|*| int  StartBlockInput   (  )
  256. ;---|*|
  257. ;---|*|         This routine begins recording the PCM data. The routine
  258. ;---|*|         returns immediately. Subsequent call must be made to
  259. ;---|*|         "ContinueBlockInput" to receive data from the DMA buffer.
  260. ;---|*|
  261. ;---|*| int  StartFileOutput   ( FILE *f, long )
  262. ;---|*|
  263. ;---|*|         This routine begins playing the PCM data from the disk file.
  264. ;---|*|         The routine returns immediately. The routine,
  265. ;---|*|         "ContinueFileOutput" must be called to continue moving data
  266. ;---|*|         from the disk to the DMA buffer. The long variable tells how
  267. ;---|*|         many bytes to play.
  268. ;---|*|
  269. ;---|*| int  StartBlockOutput  ( char far * )
  270. ;---|*|
  271. ;---|*|         This routine begins playing the caller's PCM data. The
  272. ;---|*|         routine returns immediately. The routine, "ContinueBlockOutput"
  273. ;---|*|         must subsequently be called to continue data output.
  274. ;---|*|
  275. ;---|*| int  ContinueFileInput    ( )
  276. ;---|*|
  277. ;---|*|         This routine checks to see if new data has been loaded into
  278. ;---|*|         the linked list of buffers. If so, the data is written to
  279. ;---|*|         disk, and the buffer is freed up.
  280. ;---|*|
  281. ;---|*| int  ContinueBlockInput ( char far * )
  282. ;---|*|
  283. ;---|*|         This routine checks to see if new data has been loaded into
  284. ;---|*|         the linked list of buffers. If so, the data is written to
  285. ;---|*|         the caller's buffer.
  286. ;---|*|
  287. ;---|*| int  ContinueFileOutput  ( )
  288. ;---|*|
  289. ;---|*|         This routine checks to see if the PCM hardware is
  290. ;---|*|         still playing. This routine MUST be called frequently to
  291. ;---|*|         maintain continuous PCM output.
  292. ;---|*|
  293. ;---|*| int  ContinueBlockOutput (char far *)
  294. ;---|*|
  295. ;---|*|         This routine checks to see if the PCM hardware is
  296. ;---|*|         still playing. The caller passes the next block to be
  297. ;---|*|         played. A non-zero return value indicates the block has
  298. ;---|*|         been queued up to be played. A zero value means the buffer
  299. ;---|*|         is currently full, please try again...
  300. ;---|*|
  301. ;---|*| void StopDMAIO          ( )
  302. ;---|*|
  303. ;---|*|         This routine is used to prematurely terminate PCM I/O.
  304. ;---|*|
  305. ;---|*| void ClosePCMBuffering ( )
  306. ;---|*|
  307. ;---|*|         This routine is used to close down the whole PCM I/O system.
  308. ;---|*|         This call MUST be made before the caller's program terminates.
  309. ;---|*|
  310. ;    \*/
  311.  
  312. ;    /*\
  313. ;---|*|----====< Code Generation >====----
  314. ;    \*/
  315.  
  316. #define BLOCKOUT    0        /* builds block output code only            */
  317. #define BLOCKIN     0        /* builds block input code only             */
  318. #define FILEOUT     0        /* builds file output code only             */
  319. #define FILEIN        0        /* builds file input code only                */
  320. #define COMMDATA    0        /* builds both common code and data         */
  321.  
  322. #ifdef    BUILDBO
  323. #undef  BLOCKOUT
  324. #define BLOCKOUT    1
  325. #endif
  326.  
  327. #ifdef    BUILDBI
  328. #undef  BLOCKIN
  329. #define BLOCKIN     1
  330. #endif
  331.  
  332. #ifdef    BUILDFO
  333. #undef  FILEOUT
  334. #define FILEOUT     1
  335. #endif
  336.  
  337. #ifdef    BUILDFI
  338. #undef  FILEIN
  339. #define FILEIN        1
  340. #endif
  341.  
  342. #ifdef    BUILDCO
  343. #undef    COMMDATA
  344. #define COMMDATA    1
  345. #endif
  346.  
  347. ;    /*\
  348. ;---|*|----====< common data for CODE and DATA generation >====----
  349. ;    \*/
  350.  
  351.         /* buffer linked list header structures                             */
  352.  
  353.         typedef struct _buffptr {
  354.             int status;                     /* 0=empty, 1=full                */
  355.             int count;                        /* # of bytes in the buffer     */
  356.             int size;                        /* total size of allocated buff */
  357.             char huge *buffer;                /* pointer to buffer data        */
  358.             struct _buffptr far *nextptr;    /* pointer to next buffer hdr    */
  359.  
  360.         } BuffData, far *BuffPtr;
  361.  
  362. #define NODIRECTION     0                    /* defines for DirectionFlag    */
  363. #define DMAINPUT        1
  364. #define DMAOUTPUT        2
  365.  
  366.  
  367. ;    /*\
  368. ;---|*|----====< Global Data >====----
  369. ;    \*/
  370.  
  371. #define QUEUESIZE    32                        /* 32 entries                    */
  372. #define QUEUEMASK    0x1F                    /* mask to circulate the count    */
  373.  
  374.         extern unsigned int MaxBuffCount;    /* # of DMA buffer divisions    */
  375.         extern unsigned int BufferSize;     /* size of each buffer division */
  376.  
  377.     /* shared global variables between the two tasks (in pcmioa.asm)        */
  378.  
  379.         extern BuffPtr HeadOfBuffers;        /* global variable head pointer */
  380.         extern int BufferDataCount;         /* # of full buffers (0=done)    */
  381.         extern int DMARunning;                /* DMA status (0=off,1=running) */
  382.         extern char huge *DMABuffPtr;        /* 128k+1 DMA buffer pointer    */
  383.         extern char far *StartOfDMABuffer;    /* start of DMA buffer pointer    */
  384.         extern int ProcessedBlockCount;     /* # of I/O blocks processed    */
  385.         extern unsigned long _file_data_length; /* size of data output        */
  386.         extern char __pcmdatasize;            /* default to 8 bit pcm         */
  387.  
  388.         extern FILE *__fptr;                /* file pointer for disk I/O    */
  389.         extern long __fptrpos;                /* file pointer position        */
  390.         extern BuffPtr __NextPtr;            /* next buffer pointer            */
  391.         extern int __DirectionFlag;         /* current I/O direction        */
  392.         extern char far* __singleblockpointer;/* single shot users buffer  */
  393.  
  394.         extern int VoiceActivatedSavedCount;/* # of I/O blocks saved        */
  395.  
  396.     /* additional prototypes                                                */
  397.  
  398.         void far  * _rfmemcpy          ( void far *, void far *, unsigned int );
  399.         void huge * _rfhmemcpy          ( void huge *,void huge *,unsigned int );
  400.         void far  * _memmalloc          ( long );
  401.         void        _memmfree          ( void far * );
  402.         int         _dofread          ( char far *, int, int );
  403.         int         _dofwrite          ( char far *, int, int );
  404.  
  405. #if BLOCKOUT
  406.         static int _loadtheblock  ( char far * );
  407. #endif
  408.  
  409. #if FILEOUT
  410.         static int _loadthebuffer ();
  411. #endif
  412.  
  413.  
  414.  
  415. ;    /*\
  416. ;---|*|-----------------====================================-----------------
  417. ;---|*|-----------------====< Start of Executable Code >====-----------------
  418. ;---|*|-----------------====================================-----------------
  419. ;    \*/
  420.  
  421. #if FILEIN
  422. ;    /*\
  423. ;---|*|----====< ASpecialContinueFileInput >====----
  424. ;---|*|
  425. ;---|*| This is a special adaptation of the standard, "ContinueDMAInput"
  426. ;---|*| routine. It will check the noise level in each block before writting
  427. ;---|*| it out to disk. This way, no data is written until a noise level
  428. ;---|*| is reached.
  429. ;---|*|
  430. ;    \*/
  431. int ASpecialContinueFileInput(noise,goflag)
  432.     int noise;    /* offset from silence                                    */
  433.     int goflag; /* record all after first block                         */
  434. {
  435. int temp;
  436.  
  437.     /* if BufferDataCount is non-zero, we must process the DMA data     */
  438.  
  439.         while (BufferDataCount) {
  440.  
  441.             /* validate the level of noise before writing  it to disk    */
  442.  
  443.                 if (MakeHalfHistoGram(__NextPtr->buffer,BufferSize,noise) ||
  444.                     (VoiceActivatedSavedCount && goflag) ) {
  445.  
  446.                     /* if not all data is written, return in error        */
  447.  
  448.                     if (_dofwrite (__NextPtr->buffer,BufferSize,fileno(__fptr)) != BufferSize) {
  449.                         StopDMAIO();
  450.                         return (0);
  451.                     }
  452.  
  453.                     VoiceActivatedSavedCount++;
  454.                 }
  455.                 else
  456.                     ProcessedBlockCount--;
  457.  
  458.             /* move to the next buffer                                    */
  459.  
  460.                 __NextPtr->count = __NextPtr->status = 0;
  461.                 __NextPtr = __NextPtr->nextptr;
  462.                 BufferDataCount--;
  463.         }
  464.  
  465.     /* if at the end of this block, reposition the stream pointer        */
  466.  
  467.         if (!DMARunning)
  468.             fseek ( __fptr, __fptrpos, SEEK_SET );
  469.  
  470.         return (DMARunning);
  471. }
  472. #endif
  473.  
  474.  
  475. #if BLOCKIN
  476. ;    /*\
  477. ;---|*|----====< ContinueBlockInput >====----
  478. ;---|*|
  479. ;---|*| This routine checks to see if another buffer can be stored in memory.
  480. ;---|*| if so, it will load copy the DMA buffer to the caller's local buffer,
  481. ;---|*| A return value of 0 indicates the caller's buffer is empty.
  482. ;---|*|
  483. ;    \*/
  484. int ContinueBlockInput(buff)
  485.     char far *buff;
  486. {
  487.  
  488.     /* if BufferDataCount is non-zero, we must move the data to memory    */
  489.  
  490.         if (BufferDataCount) {
  491.  
  492.             /* data is available, just move it out                        */
  493.  
  494.                 _rfmemcpy (buff,__NextPtr->buffer,BufferSize);
  495.  
  496.             /* move to the next buffer                                    */
  497.  
  498.                 __NextPtr->count = __NextPtr->status = 0;
  499.                 __NextPtr = __NextPtr->nextptr;
  500.                 BufferDataCount--;
  501.  
  502.             /* returns the fact that the data has been loaded            */
  503.  
  504.                 return(1);
  505.         }
  506.         return (0);
  507. }
  508. #endif
  509.  
  510.  
  511. #if FILEIN
  512. ;    /*\
  513. ;---|*|----====< ContinueFileInput >====----
  514. ;---|*|
  515. ;---|*| This routine checks to see if another buffer can be written to disk.
  516. ;---|*| if so, it will load copy the buffer to a local buffer, then write it
  517. ;---|*| out to disk. A return value of 0 indicates recording has stopped,
  518. ;---|*| which could mean that the disk file is full, so the DMA had to be
  519. ;---|*| stopped prematurely.
  520. ;---|*|
  521. ;    \*/
  522. int ContinueFileInput()
  523. {
  524.  
  525.     /* if BufferDataCount is non-zero, we must write out the data        */
  526.  
  527.         while (BufferDataCount) {
  528.  
  529.             /* data is available, move it out to disk                    */
  530.  
  531.             /* if not all data is written, return in error                */
  532.  
  533.                 if (_dofwrite (__NextPtr->buffer,BufferSize,fileno(__fptr)) != BufferSize) {
  534.                     StopDMAIO();
  535.                     return (0);
  536.                 }
  537.  
  538.             /* move to the next buffer                                  */
  539.  
  540.                 __NextPtr->status = 0;
  541.                 __NextPtr = __NextPtr->nextptr;
  542.                 BufferDataCount--;
  543.         }
  544.  
  545.     /* if at the end of this block, reposition the stream pointer       */
  546.  
  547.         if (!DMARunning)
  548.             fseek ( __fptr, __fptrpos, SEEK_SET );
  549.  
  550.         return (DMARunning);
  551. }
  552. #endif
  553.  
  554.  
  555. #if BLOCKOUT
  556. ;    /*\
  557. ;---|*|----====< ContinueBlockOutput >====----
  558. ;---|*|
  559. ;---|*| This routine checks to see if another DMA buffer can be loaded.
  560. ;---|*| If so, it will load the user's block data into an empty buffer.
  561. ;---|*| A return value of 1 indicates the buffer has been loaded, else
  562. ;---|*| it must be sent in again until it is loaded.
  563. ;---|*|
  564. ;    \*/
  565. int ContinueBlockOutput(buff)
  566.     char far *buff;
  567. {
  568.  
  569.     /* if the internal count is not max-ed out, try to load the next buffer */
  570.  
  571.         if (BufferDataCount < MaxBuffCount ) {
  572.  
  573.             _loadtheblock (buff);
  574.  
  575.             if (DMARunning == 0) {        /* yuck! a DMA break!            */
  576.                 _resetbuffers();
  577.                 StartTheDMAOutput(0);
  578.             }
  579.  
  580.             return (1);                 /* return running                */
  581.         }
  582.         else
  583.             return(0);
  584. }
  585. #endif
  586.  
  587.  
  588. #if FILEOUT
  589. ;    /*\
  590. ;---|*|----====< ContinueFileOutput >====----
  591. ;---|*|
  592. ;---|*| This routine checks to see if another buffer can be loaded. If so, it
  593. ;---|*| will load the data into an empty buffer. All empty buffers will be
  594. ;---|*| loaded. A return value of 0 indicates playing has finished.
  595. ;---|*|
  596. ;    \*/
  597. int ContinueFileOutput()
  598. {
  599.  
  600.     /* if BufferDataCount is not max-ed out, try to load the next buffer*/
  601.  
  602.         if (BufferDataCount < MaxBuffCount ) {
  603.  
  604.             if (_loadthebuffer()) {
  605.  
  606.                 if (DMARunning == 0) {     /* yuck! a DMA break!            */
  607.                     _resetbuffers();
  608.                     if (StartTheDMAOutput(0))
  609.                         return(0);
  610.                 }
  611.             }
  612.         }
  613.  
  614.     /* if at the end of this block, reposition the stream pointer        */
  615.  
  616.         if (!DMARunning)
  617.             fseek ( __fptr, __fptrpos, SEEK_SET );
  618.  
  619.         return (DMARunning);            /* return the DMA state         */
  620. }
  621. #endif
  622.  
  623.  
  624. #if BLOCKIN
  625. ;    /*\
  626. ;---|*|----====< StartBlockInput >====----
  627. ;---|*|
  628. ;---|*| This routine resets the buffer pointers, then starts up
  629. ;---|*| the DMA PCM input. Nothing else needs to be done. A return
  630. ;---|*| value of 0 indicates the DMA failed to startup; No input
  631. ;---|*| is occuring.
  632. ;---|*|
  633. ;    \*/
  634. int StartBlockInput()
  635. {
  636.  
  637.     /* setup our internal direction flag                                */
  638.  
  639.         __DirectionFlag = DMAINPUT;
  640.  
  641.     /* Reset the # of blocks seen during I/O processing                 */
  642.  
  643.         ProcessedBlockCount = 0;
  644.  
  645.     /* Flush all buffers                                                */
  646.  
  647.         _resetbuffers();
  648.  
  649.     /* if the hardware level code isn't gonna work, then return a failure. */
  650.  
  651.         return (!StartTheDMAInput(0));
  652. }
  653. #endif
  654.  
  655.  
  656. #if FILEIN
  657. ;    /*\
  658. ;---|*|----====< StartFileInput >====----
  659. ;---|*|
  660. ;---|*| This routine resets the buffer pointers, then starts up the DMA PCM
  661. ;---|*| input. Nothing else needs to be done.
  662. ;---|*|
  663. ;    \*/
  664. int StartFileInput(f)
  665.    FILE *f;
  666. {
  667.  
  668.     /* save our local file handle                                        */
  669.  
  670.         __fptr      = f;
  671.         __fptrpos = ftell(f);
  672.  
  673.     /* setup our internal direction flag                                */
  674.  
  675.         __DirectionFlag = DMAINPUT;
  676.  
  677.     /* Reset the # of blocks seen during I/O processing                 */
  678.  
  679.         ProcessedBlockCount = 0;
  680.  
  681.     /* Flush all buffers and other stuff..                                */
  682.  
  683.         _resetbuffers();
  684.         VoiceActivatedSavedCount = 0;
  685.  
  686.     /* start the DMA engine                                             */
  687.  
  688.         return (!StartTheDMAInput(0));
  689. }
  690. #endif
  691.  
  692.  
  693. #if BLOCKOUT
  694. ;    /*\
  695. ;---|*|----====< StartBlockOutput >====----
  696. ;---|*|
  697. ;---|*| This routine allocates and loads the necessary buffers with data from
  698. ;---|*| the PCM disk file. Upon return, if there is data available, the
  699. ;---|*| background task will be called to start the DMA. The file handle will
  700. ;---|*| be saved in a global variable to be access from other foreground
  701. ;---|*| routines. a non-zero return value indicates PCM output is playing.
  702. ;---|*|
  703. ;    \*/
  704. int StartBlockOutput(buff)
  705.     char far *buff;
  706. {
  707.  
  708.     /* setup our internal direction flag                                */
  709.  
  710.         __DirectionFlag = DMAOUTPUT;
  711.  
  712.     /* Reset the # of blocks seen during I/O processing                 */
  713.  
  714.         ProcessedBlockCount = 0;
  715.  
  716.     /* load the DMA buffers                                             */
  717.  
  718.         _resetbuffers();
  719.         _loadtheblock (buff);
  720.  
  721.     /* return good or bad if the engine is started                        */
  722.  
  723.         return (!StartTheDMAOutput(0));
  724. }
  725. #endif
  726.  
  727.  
  728. #if FILEOUT
  729. ;    /*\
  730. ;---|*|----====< StartFileOutput >====----
  731. ;---|*|
  732. ;---|*| This routine allocates and loads the necessary buffers with data from
  733. ;---|*| the PCM disk file. Upon return, if there is data available, the
  734. ;---|*| background task will be called to start the DMA. The file handle will
  735. ;---|*| be saved in a global variable to be access from other foreground
  736. ;---|*| routines. a non-zero return value indicates PCM output is playing.
  737. ;---|*|
  738. ;    \*/
  739. int StartFileOutput(f,len)
  740.     FILE *f;
  741.     long len;
  742. {
  743.  
  744.     /* save our local file handle                                        */
  745.  
  746.         __fptr = f;
  747.         __fptrpos = ftell(f);
  748.  
  749.     /* setup our internal direction flag, and the desired length        */
  750.  
  751.         __DirectionFlag   = DMAOUTPUT;
  752.         _file_data_length = len;
  753.  
  754.     /* Reset the # of blocks seen during I/O processing                 */
  755.  
  756.         ProcessedBlockCount = 0;
  757.  
  758.     /* if any data is loaded into the buffer, start the DMA & return    */
  759.  
  760.         _resetbuffers();
  761.  
  762.         do {
  763.  
  764.             /* get the next buffer full & exit if done                    */
  765.  
  766.             if (!_loadthebuffer())
  767.                 break;
  768.  
  769.         } while (__NextPtr != HeadOfBuffers);
  770.  
  771.     /* return good or bad if the engine is running                        */
  772.  
  773.         return (!StartTheDMAOutput(0));
  774.  
  775. }
  776. #endif
  777.  
  778.  
  779. #if BLOCKOUT
  780. ;    /*\
  781. ;---|*|----====< _loadtheblock >====----
  782. ;---|*|
  783. ;---|*| This routine loads the block into the DMA buffer.
  784. ;---|*|
  785. ;    \*/
  786. static int _loadtheblock(buff)
  787.     char far *buff;
  788. {
  789.  
  790.     /* load the block of data into the DMA buffer                        */
  791.  
  792.         _rfmemcpy(__NextPtr->buffer, buff, BufferSize );
  793.  
  794.     /* now that the data is secure, fill out the rest of the header to    */
  795.     /* allow the background process to "see" this new data              */
  796.  
  797.         __NextPtr->status = 1;
  798.         __NextPtr->count  = BufferSize;
  799.         __NextPtr          = __NextPtr->nextptr; /* advance the list     */
  800.         BufferDataCount++;
  801.  
  802.     /* we have data, return the size                                    */
  803.  
  804.        return (BufferSize);
  805. }
  806. #endif
  807.  
  808.  
  809. #if FILEOUT
  810. ;    /*\
  811. ;---|*|----====< _loadthebuffer >====----
  812. ;---|*|
  813. ;---|*| This routine loads the disk contents into an available buffer.
  814. ;---|*| A return value of 0 indicates no more data has been loaded.
  815. ;---|*|
  816. ;    \*/
  817. static int _loadthebuffer()
  818. {
  819. char huge *s;
  820. register int n;
  821. long l;
  822.  
  823.     /* reset the header data                                            */
  824.  
  825.         __NextPtr->count = __NextPtr->status = 0;
  826.  
  827.     /* exit if there is no data to be read                                */
  828.  
  829.         if (feof (__fptr) || (!_file_data_length))
  830.             return (0);
  831.  
  832.     /* adjust the max count we want to process from the file            */
  833.  
  834.         if (_file_data_length <= BufferSize) {
  835.             l = _file_data_length;
  836.             _file_data_length = 0;
  837.         }
  838.         else {
  839.             _file_data_length -= (l = (BufferSize & 0xffff));
  840.         }
  841.  
  842.     /* read the data from the file                                        */
  843.  
  844.         if((n = _dofread (__NextPtr->buffer, ((int)(l & 0xffff)),fileno(__fptr) )) == 0)
  845.             return(0);
  846.  
  847.         s = __NextPtr->buffer+n; // point to the end of the block
  848.  
  849.     // flush to the end if not a full buffer worth of data
  850.  
  851.         if (n < BufferSize)
  852.             FlushBuffer (s,BufferSize-n);
  853.  
  854.     /* now that the data is secure, fill out the rest of the header to    */
  855.     /* allow the background process to "see" this new data              */
  856.  
  857.         __NextPtr->status = 1;
  858.         __NextPtr->count  = BufferSize;
  859.         __NextPtr          = __NextPtr->nextptr; /* advance the list     */
  860.         BufferDataCount++;
  861.  
  862.     /* we have data, return the size                                    */
  863.  
  864.        return (n);
  865. }
  866. #endif
  867.  
  868. ;   /*\
  869. ;---|*| end of PCMIOC.C
  870. ;    \*/
  871.  
  872.